package com.easygoods.service;

import com.bestvike.stone.core.lang.BeanUtils;
import com.bestvike.stone.core.lang.Convert;
import com.bestvike.stone.core.lang.RandomUtils;
import com.bestvike.stone.core.time.DateUtils;
import com.bestvike.stone.spring.exception.BusinessException;
import com.bestvike.stone.spring.exception.ErrorCode;
import com.bestvike.stone.spring.page.PageableRequest;
import com.bestvike.stone.spring.page.PageableResponse;
import com.bestvike.stone.spring.service.BaseService;
import com.easygoods.bean.MemberCouponRecordBean;
import com.easygoods.dao.MemberCouponDao;
import com.easygoods.dao.MemberCouponRecordDao;
import com.easygoods.dao.MemberInfoDao;
import com.easygoods.entity.MemberCoupon;
import com.easygoods.entity.MemberCouponRecord;
import com.easygoods.enums.CouponState;
import com.easygoods.request.CouponListRequest;
import com.easygoods.response.CouponRecordResponse;
import com.easygoods.response.CouponResponse;
import com.easygoods.response.CouponResponseItem;
import com.easygoods.shiro.auth.UserAuth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import tk.mybatis.mapper.entity.Example;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * Created by 许崇雷 on 2019-01-17.
 */
@SuppressWarnings("Duplicates")
@Service
public class CouponService extends BaseService {
    @Autowired
    private MemberCouponDao memberCouponDao;
    @Autowired
    private MemberCouponRecordDao memberCouponRecordDao;
    @Autowired
    private MemberInfoDao memberInfoDao;

    //新增代金券操作记录
    private void addCouponRecord(MemberCouponRecordBean memberCouponRecordBean) {
        MemberCouponRecord memberCouponRecord = new MemberCouponRecord();
        memberCouponRecord.setId(RandomUtils.randomUUID());
        memberCouponRecord.setCouponId(memberCouponRecordBean.getCouponId());
        memberCouponRecord.setAmount(memberCouponRecordBean.getAmount());
        memberCouponRecord.setReason(memberCouponRecordBean.getReason());
        memberCouponRecord.setAcpMemberId(memberCouponRecordBean.getAcpMemberId());
        memberCouponRecord.setAcpMemberMobile(memberCouponRecordBean.getAcpMemberMobile());
        memberCouponRecord.setRefGainOrderId(memberCouponRecordBean.getRefGainOrderId());
        memberCouponRecord.setRefPayOrderId(memberCouponRecordBean.getRefPayOrderId());
        memberCouponRecord.setMemberId(memberCouponRecordBean.getMemberId());
        memberCouponRecord.beforeInsert();
        int recordNum = this.memberCouponRecordDao.insert(memberCouponRecord);
        if (recordNum != 1) {
            this.log.error("新增用户代金券流水表失败");
            throw new BusinessException(ErrorCode.ERROR_SERVER, "代金券操作失败");
        }
    }

    //获取提示信息
    private String getWarnInfo(CouponState state) {
        if (state == null)
            return "该代金券状态异常";
        switch (state) {
            case Used:
                return "该代金券已经使用过了";
            case Expired:
                return "该代金券已经过期";
            case Cancelled:
                return "该代金券已经作废";
            default:
                return "该代金券状态异常";
        }
    }

    //获取用户退货时提示信息
    private String getReturnWarnInfo(CouponState state) {
        if (state == null)
            return "该代金券状态异常";
        switch (state) {
            case Normal:
                return "该代金券未被使用";
            case Expired:
                return "该代金券已经过期";
            case Cancelled:
                return "该代金券已经作废";
            default:
                return "该代金券状态异常";
        }
    }

    //生成代金券
    @Transactional
    public void addCoupon(String memberId, String acpMemberId, String acpMemberMobile, BigDecimal couponAmount, int validDays, String reason, String refOrderId) {
        Assert.hasText(memberId, "memberId can not be empty");
        Assert.notNull(couponAmount, "couponAmount不能为空");
        Assert.isTrue(couponAmount.compareTo(BigDecimal.ZERO) > 0, "couponAmount金额不能小于0");
        Assert.isTrue(validDays > 0, "代金券validDays不能小于0");
        Assert.hasText(reason, "reason不能为空");

        //更新用户历史获取的代金券的总金额
        final int updateCount = this.memberInfoDao.increaseInviteCoupon(memberId, couponAmount);
        if (updateCount != 1) {
            this.log.info("更新历史代金券总金额失败 memberId:" + memberId);
            throw new BusinessException(ErrorCode.ERROR_SERVER, "无效的用户");
        }

        //生成代金券
        MemberCoupon memberCoupon = new MemberCoupon();
        memberCoupon.setId(RandomUtils.randomUUID());
        memberCoupon.setMemberId(memberId);
        memberCoupon.setAmount(couponAmount);
        String nowYearString = DateUtils.nowDateString().substring(0, 4).trim();
        Integer nowYearInt = Integer.parseInt(nowYearString);
        memberCoupon.setGainYear(nowYearInt);
        Date expireTime = DateUtils.addDays(DateUtils.now(), validDays);
        memberCoupon.setGainReason("邀请用户注册获得");
        memberCoupon.setExpireTime(expireTime);
        memberCoupon.setAcpMemberId(acpMemberId);//被邀请人
        memberCoupon.setAcpMemberMobile(acpMemberMobile);//被邀请人手机号
        memberCoupon.setState(CouponState.Normal.name());
        memberCoupon.beforeInsert();
        int memberCouponNum = this.memberCouponDao.insert(memberCoupon);
        if (memberCouponNum != 1) {
            this.log.error("新增用户代金券表失败");
            throw new BusinessException(ErrorCode.ERROR_SERVER, "代金券增加失败");
        }

        //代金券流水
        MemberCouponRecordBean memberCouponRecordBean = new MemberCouponRecordBean();
        memberCouponRecordBean.setCouponId(memberCoupon.getId());
        memberCouponRecordBean.setAmount(couponAmount);
        memberCouponRecordBean.setMemberId(memberId);
        //用户购买商品或邀请其他用户
        memberCouponRecordBean.setReason(reason);
        memberCouponRecordBean.setAcpMemberId(memberCoupon.getAcpMemberId());
        memberCouponRecordBean.setAcpMemberMobile(memberCoupon.getAcpMemberMobile());
        memberCouponRecordBean.setRefGainOrderId(refOrderId);
        memberCouponRecordBean.setRefPayOrderId(null);
        this.addCouponRecord(memberCouponRecordBean);
    }

    //消费代金券
    @Transactional
    public MemberCoupon consumeCoupon(String memberId, String couponId, String orderId) {
        Assert.hasText(memberId, "memberId can not be empty");
        Assert.hasText(couponId, "couponId不能为空");
        Assert.hasText(orderId, "orderId不能为空");

        MemberCoupon memberCoupon = this.getMemberCoupon(memberId, couponId);
        if (DateUtils.now().compareTo(memberCoupon.getExpireTime()) > 0) {
            throw new BusinessException(ErrorCode.ERROR_SERVER, "该代金券已经过了有效期，无法消费");
        }
        CouponState couponState = Convert.toType(memberCoupon.getState(), CouponState.class);
        if (couponState != CouponState.Normal)
            throw new BusinessException(ErrorCode.ERROR_SERVER, this.getWarnInfo(couponState));

        MemberCoupon memberCouponUpdate = new MemberCoupon();
        memberCouponUpdate.setId(couponId);
        memberCouponUpdate.setState(CouponState.Used.name());
        memberCouponUpdate.beforeUpdate();
        int updateNum = this.memberCouponDao.updateByPrimaryKeySelective(memberCouponUpdate);
        if (updateNum != 1) {
            this.log.error("更新代金券表代金券状态失败");
            throw new BusinessException(ErrorCode.ERROR_SERVER, "消费代金券失败");
        }
        MemberCouponRecordBean memberCouponRecordBean = new MemberCouponRecordBean();
        memberCouponRecordBean.setAmount(memberCoupon.getAmount().negate());
        memberCouponRecordBean.setCouponId(couponId);
        memberCouponRecordBean.setMemberId(memberId);
        memberCouponRecordBean.setReason("用户购买商品,消费代金券");
        memberCouponRecordBean.setAcpMemberId(memberCoupon.getAcpMemberId());
        memberCouponRecordBean.setAcpMemberMobile(memberCoupon.getAcpMemberMobile());
        memberCouponRecordBean.setRefGainOrderId(null);
        memberCouponRecordBean.setRefPayOrderId(orderId);
        this.addCouponRecord(memberCouponRecordBean);
        return memberCoupon;
    }

    //根据代金券id获取代金券记录，需要加排它锁
    private MemberCoupon getMemberCoupon(String memberId, String couponId) {
        Example memberCouponExample = new Example(MemberCoupon.class);
        memberCouponExample.createCriteria().andEqualTo(MemberCoupon.ID, couponId).andEqualTo(MemberCoupon.MEMBER_ID, memberId);
        memberCouponExample.setForUpdate(true);
        MemberCoupon memberCoupon = this.memberCouponDao.selectOneByExample(memberCouponExample);
        if (memberCoupon == null)
            throw new BusinessException(ErrorCode.ERROR_SERVER, "无效的代金券");
        return memberCoupon;
    }

    //获取可用的代金券,无锁
    public MemberCoupon getValidMemberCoupon(String memberId, String couponId) {
        Example memberCouponExample = new Example(MemberCoupon.class);
        memberCouponExample.createCriteria()
                .andEqualTo(MemberCoupon.ID, couponId)
                .andEqualTo(MemberCoupon.MEMBER_ID, memberId);
        MemberCoupon memberCoupon = this.memberCouponDao.selectOneByExample(memberCouponExample);
        if (memberCoupon == null)
            throw new BusinessException(ErrorCode.ERROR_SERVER, "无效的代金券");
        if (DateUtils.now().compareTo(memberCoupon.getExpireTime()) > 0)
            throw new BusinessException(ErrorCode.ERROR_SERVER, "该代金券已经过了有效期，无法消费");
        CouponState couponState = Convert.toType(memberCoupon.getState(), CouponState.class);
        if (couponState != CouponState.Normal)
            throw new BusinessException(ErrorCode.ERROR_SERVER, this.getWarnInfo(couponState));
        return memberCoupon;
    }

    //作废代金券
    @Transactional
    public void cancelCoupon(String memberId, String couponId) {
        Assert.hasText(couponId, "couponId不能为空");

        MemberCoupon memberCoupon = this.getMemberCoupon(memberId, couponId);
        if (DateUtils.now().compareTo(memberCoupon.getExpireTime()) > 0) {
            throw new BusinessException(ErrorCode.ERROR_SERVER, "该代金券已经过了有效期，无法作废");
        }
        CouponState couponState = Convert.toType(memberCoupon.getState(), CouponState.class);
        BigDecimal amount = memberCoupon.getAmount();
        if (couponState != CouponState.Normal)
            throw new BusinessException(ErrorCode.ERROR_SERVER, this.getWarnInfo(couponState));

        MemberCoupon memberCouponUpdate = new MemberCoupon();
        memberCouponUpdate.setId(couponId);
        memberCouponUpdate.setState(CouponState.Cancelled.name());
        memberCouponUpdate.beforeUpdate();
        int updateNum = this.memberCouponDao.updateByPrimaryKeySelective(memberCouponUpdate);
        if (updateNum != 1) {
            this.log.error("更新代金券表代金券状态失败");
            throw new BusinessException(ErrorCode.ERROR_SERVER, "代金券状态流转失败");
        }
        MemberCouponRecordBean memberCouponRecordBean = new MemberCouponRecordBean();
        memberCouponRecordBean.setAmount(amount);
        memberCouponRecordBean.setCouponId(couponId);
        memberCouponRecordBean.setMemberId(memberId);
        memberCouponRecordBean.setReason("将该代金券作废");
        memberCouponRecordBean.setAcpMemberId(memberCoupon.getAcpMemberId());
        memberCouponRecordBean.setAcpMemberMobile(memberCoupon.getAcpMemberMobile());
        memberCouponRecordBean.setRefGainOrderId(null);
        memberCouponRecordBean.setRefPayOrderId(null);
        this.addCouponRecord(memberCouponRecordBean);
    }

    //代金券过期
    @Transactional
    public void expireCoupon(String memberId, String couponId) {
        Assert.hasText(couponId, "couponId不能为空");


        Example memberCouponExample = new Example(MemberCoupon.class);
        memberCouponExample.createCriteria().andEqualTo(MemberCoupon.ID, couponId).andEqualTo(MemberCoupon.MEMBER_ID, memberId);
        MemberCoupon memberCoupon = this.memberCouponDao.selectOneByExample(memberCouponExample);
        if (memberCoupon == null) {
            this.log.warn("无此代金券");
            return;
        }
        BigDecimal amount = memberCoupon.getAmount();

        Example example = new Example(MemberCoupon.class);
        example.createCriteria().andEqualTo(MemberCoupon.ID, couponId)
                .andEqualTo(MemberCoupon.STATE, CouponState.Normal.name());
        MemberCoupon memberCouponUpdate = new MemberCoupon();
        memberCouponUpdate.setState(CouponState.Expired.name());
        memberCouponUpdate.beforeUpdate();
        int updateNum = this.memberCouponDao.updateByExampleSelective(memberCouponUpdate, example);
        if (updateNum != 1) {
            this.log.warn("更新代金券表代金券状态失败,该代金券可能已被修改,couponId:" + couponId);
            return;
        }
        MemberCouponRecordBean memberCouponRecordBean = new MemberCouponRecordBean();
        memberCouponRecordBean.setAmount(amount);
        memberCouponRecordBean.setCouponId(couponId);
        memberCouponRecordBean.setMemberId(memberId);
        memberCouponRecordBean.setReason("该代金券过期");
        memberCouponRecordBean.setAcpMemberId(memberCoupon.getAcpMemberId());
        memberCouponRecordBean.setAcpMemberMobile(memberCoupon.getAcpMemberMobile());
        memberCouponRecordBean.setRefGainOrderId(null);
        memberCouponRecordBean.setRefPayOrderId(null);
        this.addCouponRecord(memberCouponRecordBean);
    }

    //用户退货后，将代金券从已使用恢复到正常
    @Transactional
    public void returnCoupon(String memberId, String couponId, String orderId) {
        Assert.hasText(couponId, "couponId不能为空");
        Assert.hasText(orderId, "orderId不能为空");

        MemberCoupon memberCoupon = this.getMemberCoupon(memberId, couponId);
        CouponState couponStateUpdate = DateUtils.now().compareTo(memberCoupon.getExpireTime()) > 0
                ? CouponState.Expired
                : CouponState.Normal;
        CouponState couponState = Convert.toType(memberCoupon.getState(), CouponState.class);
        BigDecimal amount = memberCoupon.getAmount();
        if (couponState != CouponState.Used)
            throw new BusinessException(ErrorCode.ERROR_SERVER, this.getReturnWarnInfo(couponState));

        MemberCoupon memberCouponUpdate = new MemberCoupon();
        memberCouponUpdate.setId(couponId);
        memberCouponUpdate.setState(couponStateUpdate.name());
        memberCouponUpdate.beforeUpdate();
        int updateNum = this.memberCouponDao.updateByPrimaryKeySelective(memberCouponUpdate);
        if (updateNum != 1) {
            this.log.error("更新代金券表代金券状态失败");
            throw new BusinessException(ErrorCode.ERROR_SERVER, "代金券状态流转失败");
        }
        MemberCouponRecordBean memberCouponRecordBean = new MemberCouponRecordBean();
        memberCouponRecordBean.setAmount(amount);
        memberCouponRecordBean.setCouponId(couponId);
        memberCouponRecordBean.setMemberId(memberId);
        memberCouponRecordBean.setReason("用户退货后,重新返还代金券给用户");
        memberCouponRecordBean.setAcpMemberId(memberCoupon.getAcpMemberId());
        memberCouponRecordBean.setAcpMemberMobile(memberCoupon.getAcpMemberMobile());
        memberCouponRecordBean.setRefGainOrderId(orderId);
        memberCouponRecordBean.setRefPayOrderId(null);
        this.addCouponRecord(memberCouponRecordBean);
    }

    //可用代金券合计
    public BigDecimal sumNormalCoupon(String memberId) {
        return this.memberCouponDao.sumNormalCoupon(memberId);
    }

    //根据代金券状态查询该会员代金券列表
    public CouponResponse getCouponList(CouponListRequest couponListRequest) {
        final UserAuth userAuth = this.getAuth();

        String couponState = couponListRequest.getCouponState() == null ? null : couponListRequest.getCouponState().name();
        List<MemberCoupon> memberCouponList = this.memberCouponDao.getMemberCouponList(userAuth.getMemberId(), couponState);

        List<CouponResponseItem> couponResponseItemList = BeanUtils.toList(memberCouponList, CouponResponseItem.class);
        CouponResponse couponResponse = new CouponResponse();
        couponResponse.setCouponList(couponResponseItemList);
        return couponResponse;
    }

    //查询该用户获得的代金券流水记录
    public PageableResponse<CouponRecordResponse> getCouponRecordList(PageableRequest pageableRequest) {
        final UserAuth userAuth = this.getAuth();
        Example example = new Example(MemberCouponRecord.class);
        example.createCriteria().andEqualTo(MemberCouponRecord.MEMBER_ID, userAuth.getMemberId()).andGreaterThan(MemberCouponRecord.AMOUNT, 0);
        example.orderBy(MemberCouponRecord.CREATE_TIME).desc();
        List<MemberCouponRecord> memberCouponRecordList = this.memberCouponRecordDao.selectByExampleAndRowBounds(example, pageableRequest.toRowBounds());
        List<CouponRecordResponse> couponRecordResponseList = BeanUtils.toList(memberCouponRecordList, CouponRecordResponse.class);
        return PageableResponse.create(memberCouponRecordList, couponRecordResponseList);
    }

    //获取过期的代金券id列表
    public List<String> getExpiredCouponList(String memberId) {
        return this.memberCouponDao.getExpiredCouponList(memberId);
    }
}
